/**
 * 
 */
package com.example.quedalouca;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;

import org.jbox2d.callbacks.ContactImpulse;
import org.jbox2d.callbacks.ContactListener;
import org.jbox2d.collision.Manifold;
import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.Fixture;
import org.jbox2d.dynamics.contacts.Contact;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.util.Log;
import android.view.MotionEvent;

import com.TangoGames.box2d.BaseActor;
import com.TangoGames.box2d.BaseDebugDraw;
import com.TangoGames.box2d.PhysicsSimulator;
import com.TangoGames.box2d.WorldPanelState;
import com.TangoGames.box2d.PhysicsSimulator.Gravitys;
import com.TangoGames.panel.IPanelElement;
import com.TangoGames.sprite.Sprite;

/**
 * @author Arthur
 *
 */
public class TestBOX2D extends WorldPanelState {

	/**
	 * TAG
	 */
	private static final String TAG = TestBOX2D.class.getSimpleName();
	
	/**
	 * 
	 */
	private Bitmap background; 
	
	/**
	 * 
	 */
	private Matrix bgMatrix;
	
	private 
	/**
	 * 
	 */
	Queue<Point> actionDownQueue = new LinkedList<Point>();
	
	/**]
	 * 
	 */
    float[]                     mAcc = null;
    float[]                     mMag = null;
	
    private Vec2 newGravity;
    
	/**
	 * 
	 */
	public TestBOX2D() {
		super();
	}

	@Override
	protected void InitializeWorld(PhysicsSimulator simulator) {
		//
		background = BitmapFactory.decodeResource(this.getBasePanel().getResources(), R.drawable.field_1);
		//
		float sx = ((float)this.getBasePanel().getScreenWidth()) / background.getWidth() ;
		//
		float sy = ((float)this.getBasePanel().getScreenHeight()) / background.getHeight(); 
		//
		bgMatrix = new Matrix();
		//
		bgMatrix.postScale( sx, sy );
		//
		newGravity = Gravitys.EARTH.getVetorialGravity();
		//
		simulator.setStepTimeFator(4.0f);
		
		//Liga o desenho para debug
		simulator.setDebugDraw(new BaseDebugDraw(this.getViewportTransform()));
		this.setDrawActors(false);
		
		//
		this.SetupViewportTransform(0, 0, 0, this.getBasePanel().getScreenHeight() , WSCALE, true);
		//
		CreateWalls(simulator);
		
		simulator.getWorld().setContactListener(new MyContactListener());
		
				
	}

	private void CreateWalls(PhysicsSimulator simulator){
		Log.d(TAG,"Witdh: "+this.getBasePanel().getScreenWidth() + "Height: " + this.getBasePanel().getScreenHeight());
		//
		Vec2 screenBounds = new Vec2(this.getBasePanel().getScreenWidth(),this.getBasePanel().getScreenHeight());
		//
		Vec2 bottonRightWorldBounds = new Vec2(); 
		//
		Vec2 topLeftWorldBounds = new Vec2(); 
		//		
		this.getViewportTransform().getScreenToWorld(screenBounds, bottonRightWorldBounds);
		//
		this.getViewportTransform().getScreenToWorld(new Vec2(0,0), topLeftWorldBounds);
		//ground	
		//simulator.createWallsAndGround(topLeftWorldBounds.x, bottonRightWorldBounds.y, screenBounds.x * WSCALE , 1.0f);
		generateBottonLine(40.0f);
		//left wall
		simulator.createWallsAndGround(topLeftWorldBounds.x - 1.0f , topLeftWorldBounds.y , 1.0f , screenBounds.y * WSCALE );
		//right wall
		simulator.createWallsAndGround(bottonRightWorldBounds.x  , topLeftWorldBounds.y , 1.0f , screenBounds.y * WSCALE);
		//ceiling
		simulator.createWallsAndGround(topLeftWorldBounds.x, topLeftWorldBounds.y + 1.0f, screenBounds.x * WSCALE , 1.0f);		
		//generate pins for list position on bitmap
		for (Point p:FindPinsOnBitmapa(background)) this.getChildrenElements().add(new Pino(this, p ));
	}
	
	/**
	 *	bottom line 
	 */
	private void generateBottonLine(float goalWidth){
		
		new BottonLine(this, new Point(0, (int)this.getBasePanel().getScreenHeight()- 2), (int)this.getBasePanel().getScreenWidth() );
		
		final float GOAL_WIDTH = 120.0f;
		new Goal(this, new Point((int)(this.getBasePanel().getScreenWidth() - GOAL_WIDTH)/2, (int)this.getBasePanel().getScreenHeight()- 4 ), GOAL_WIDTH );
	}
	
	
	/**
	 * Scan a bitmap search a color (r 255, green 255, blue 128) and generate a list of points in respective screen  
	 * @param bitmap
	 * bitmap base of scan
	 * @return
	 */
	private List<Point> FindPinsOnBitmapa(Bitmap bitmap){
		//List of points
		List<Point> lp = new ArrayList<Point>();
		//ratio of size screen and bitmap
		float sx = ((float)this.getBasePanel().getScreenWidth()) / background.getWidth() ;
		float sy = ((float)this.getBasePanel().getScreenHeight()) / background.getHeight();
		//scan for the color
		for (int y=0 ; y< bitmap.getHeight() ; y++){
			for (int x=0 ; x< bitmap.getWidth() ; x++){
		        int pix = bitmap.getPixel(x,y);
		        int red = Color.red(pix);
		        int blue = Color.blue(pix);
		        int green = Color.green(pix);
		        //find the color and generate
		        if ( red==255 && blue==255 && green==128 ) lp.add(new Point((int)(x*sx),(int)(y*sy)));
			}
		}   
		return lp;
	}
	
	@Override
	public void Draw(PhysicsSimulator simulator, Canvas canvas) {
			//canvas.drawColor(Color.BLACK);
			//canvas.drawBitmap(background,bgMatrix, new Paint(Paint.ANTI_ALIAS_FLAG));
			//Paint paint = new Paint();
			//paint.setColor(Color.WHITE);
			//Drawteste(simulator, canvas);
			//int VIEW_WIDTH = canvas.getWidth();
			//int VIEW_HEIGHT = canvas.getHeight();
			//for (int i= 0; i <VIEW_WIDTH; i+=25)	{ canvas.drawLine(i, 0 , i, VIEW_HEIGHT, paint); } 
			//for (int i= 0; i <VIEW_HEIGHT; i+=25)	{ canvas.drawLine(0, i , VIEW_WIDTH , i, paint); } 
	}

	@Override
	public void Update(PhysicsSimulator simulator, long gameTime) {
		//setup gravity
		simulator.getWorld().setGravity(newGravity);

		//Log.d(TAG,"gravity: " + newGravity.toString());
		
		//create new body
        if (actionDownQueue.size()>0) {
        	synchronized (actionDownQueue) {
        		Point p = actionDownQueue.poll();
    			this.getChildrenElements().add(new Ball(this, p ) );
        		
            	/**Random r = new Random();
            	switch (r.nextInt(4)) {
            		case 0:
            			this.getChildrenElements().add(new Crate(this, p ) );
            			break;
            		case 1:
            			this.getChildrenElements().add(new Ball(this, p ) );
            			break;
            		case 2:
            			this.getChildrenElements().add(new Crate(this, p ) );
            			break;
            		case 3:
            			this.getChildrenElements().add(new Ball(this, p ) );
            			break;
            	}*/
        	}
        }
	}

	@Override
	public void Destroy(){
		super.Destroy();
	}
	
	private void Drawteste(PhysicsSimulator simulator, Canvas canvas){ 	
		Body body = simulator.getWorld().getBodyList();
		while (body != null) {
			Vec2 position = body.getPosition();
			//Log.d(TAG, body.toString() + ": position= " + position.toString());
			//Fixture fixture = body.getFixtureList();
			//Shape shape = fixture.getShape();
			//if (shape instanceof CircleShape) {
				//CircleShape circleShape = (CircleShape) shape;
				//paint.setColor(0xFF440000);
			    //canvas.drawCircle(position.x, position.y,
			    //circleShape.m_radius, paint);
			//}
			body = body.getNext();
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (super.onTouchEvent(event)) { return true;}
		//
		int action = event.getAction();
		//
	    switch (action) {
        	case MotionEvent.ACTION_DOWN:
        		// finger touches the screen
        		synchronized (actionDownQueue) {
        			actionDownQueue.add(new Point( (int)event.getX() , (int)event.getY() ) );
        		}
        	case MotionEvent.ACTION_MOVE:
        		// finger moves on the screen
        		break;

        	case MotionEvent.ACTION_UP:   
        		// finger leaves the screen
        		break;
	    }
		return true;
	}

	

	@Override
	public boolean isDrawable() {
		// TODO Auto-generated method stub
		return false;
	}

	class Crate extends BaseActor{
		public Crate(WorldPanelState worldPanel, Point position) {
			
			super(worldPanel , new Sprite(BitmapFactory.decodeResource(worldPanel.getBasePanel().getResources(), R.drawable.crate),  position.x, position.y) , position, false );				
		}
	}
	
	class Ball extends BaseActor{
		public Ball(WorldPanelState worldPanel, Point position) {
			super(worldPanel,position);
			Sprite s = new Sprite(BitmapFactory.decodeResource(worldPanel.getBasePanel().getResources(), R.drawable.soccer_ball),  position.x, position.y) ;
			s.centerDrawReference();
			this.CreateBodyActor( s , position, true );	
		}
	}

	class Pino extends BaseActor{
		public Pino(WorldPanelState worldPanel, Point position) {
			super(worldPanel,position);
			
			this.sprite = new Sprite(BitmapFactory.decodeResource(worldPanel.getBasePanel().getResources(), R.drawable.tennis_ball),  position.x, position.y) ;
			
			this.sprite.centerDrawReference();				
			
			Vec2 pos = new Vec2(position.x, position.y);

			Vec2 wordpos = new Vec2();
			
			viewportTransform.getScreenToWorld(pos, wordpos);

			//Log.d("BaseActor", "pino with: " + this.sprite.getWidth() + " raio scala: " + (this.sprite.getWidth() / WSCALE * 2));
			
			this.worldBody 	= worldPanel.getSimulator().createWallsAndGround( wordpos.x , wordpos.y , this.sprite.getWidth() / ( WSCALE * 2 ) , this);
			
		}
		
	}

	class BottonLine extends BaseActor{
		public BottonLine(WorldPanelState worldPanel, Point position, float width ) {
			super(worldPanel,position);
			
			this.sprite = null ;
			
			Vec2 pos = new Vec2(position.x, position.y);

			Vec2 wordpos = new Vec2();
			
			viewportTransform.getScreenToWorld(pos, wordpos);
		
			this.worldBody 	= worldPanel.getSimulator().createWallsAndGround( wordpos.x , wordpos.y , width , WSCALE , this, false );
			
		}
		
		@Override
		public void Draw(Canvas canvas){
			//do nothing
		}
		
		
	}

	class Goal extends BaseActor{
		public Goal(WorldPanelState worldPanel, Point position, float width ) {
			super(worldPanel,position);
			
			this.sprite = null ;
			
			Vec2 pos = new Vec2(position.x, position.y);

			Vec2 wordpos = new Vec2();
			
			viewportTransform.getScreenToWorld(pos, wordpos);
		
			this.worldBody 	= worldPanel.getSimulator().createWallsAndGround( wordpos.x , wordpos.y , width / WSCALE , WSCALE , this, false );
			
		}
		
		@Override
		public void Draw(Canvas canvas){
			//do nothing
		}
		
		
	}

	
	
	@Override
	public void onSensorChanged(SensorEvent event) {
        Sensor sensor = event.sensor;
        
        switch (sensor.getType())
        {
            case Sensor.TYPE_ACCELEROMETER:
                // Log.d(TAG, "acc");
            	mAcc = event.values.clone();
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
                // Log.d(TAG, "mag");
            	mMag = event.values.clone();
                break;
        }
        
        if (mAcc == null || mMag == null)
        {
            return;
        }
        //Log.d(TAG, "or " + mAcc[0] + "," + mAcc[1] + "," + mAcc[2]);

        
        newGravity.x = -mAcc[0];
        newGravity.y = -mAcc[1];
        //newGravity.mul(Gravitys.EARTH.getEscalarGravity());
        
        //if (elH.world!=null)
        //{
        //    elH.world.setGravity(gravity);
        //}
        /*
         * float R[] = new float[9]; float mOrientation[] = new float[3]; if (SensorManager.getRotationMatrix(R, null, mAcc,
         * mMag)) {
         * 
         * SensorManager.getOrientation(R, mOrientation); Log.d(TAG, "or " + mOrientation[0] + "," + mOrientation[1] + "," +
         * mOrientation[2]); }
         */
        
	}	

	class MyContactListener implements ContactListener{

		@Override
		public void beginContact(Contact contact) {
			if (contact.getFixtureA().getBody().getUserData() instanceof BottonLine || contact.getFixtureB().getBody().getUserData() instanceof BottonLine) {
				if (contact.getFixtureA().getBody().getUserData() instanceof Ball) {
					((Ball)contact.getFixtureA().getBody().getUserData()).setMarkToRemove(true);
				}
				else if (contact.getFixtureB().getBody().getUserData() instanceof Ball) {
					((Ball)contact.getFixtureB().getBody().getUserData()).setMarkToRemove(true);
				}

				Log.d("MyContactListener", "Bateu na linha de fundo" );
			}
			if (contact.getFixtureA().getBody().getUserData() instanceof Goal || contact.getFixtureB().getBody().getUserData() instanceof Goal) {  
				if (contact.getFixtureA().getBody().getUserData() instanceof Ball) {
					((Ball)contact.getFixtureA().getBody().getUserData()).setMarkToRemove(true);
				}
				else if (contact.getFixtureB().getBody().getUserData() instanceof Ball) {
					((Ball)contact.getFixtureB().getBody().getUserData()).setMarkToRemove(true);
				}
				Log.d("MyContactListener", "GOOOOOOOOOOOOOLLLL!!!!" );
			}

		}

		@Override
		public void endContact(Contact contact) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void postSolve(Contact arg0, ContactImpulse arg1) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void preSolve(Contact arg0, Manifold arg1) {
			// TODO Auto-generated method stub
			
		}
		
	}
	
}
